package com.demo.socketchannel;

import com.alibaba.fastjson.JSON;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;

/**
 * @author MT
 * SocketChannel 处理器
 * @date 2019-12-10 11:18
 */
public class Handler {

    private int bufferSize = 1024;
    private String localCharset = "UTF-8";

    public Handler() {

    }

    public Handler(int bufferSize) {
        this(bufferSize, null);
    }

    public Handler(String localCharset) {
        this(-1, localCharset);
    }

    public Handler(int bufferSize, String localCharset) {
        if (bufferSize > 0) {
            this.bufferSize = bufferSize;
        }
        if (localCharset != null) {
            this.localCharset = localCharset;
        }
    }

    // 接收到链接请求超时
    public void handleAccept(SelectionKey key) throws IOException {
        // 通过选择器键获取服务器套接字通道，通过accept()方法获取套接字通道连接
        SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
        // 设置套接字通道为非阻塞模式
        socketChannel.configureBlocking(false);
        // 为套接字通道注册选择器，该选择器为服务器套接字通道的选择器，即选择到该SocketChannel的选择器
        // 设置选择器关心请求为读操作，设置数据读取的缓冲器容量为处理器初始化时候的缓冲器容量
        socketChannel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
    }


    public void handleRead(SelectionKey key) throws IOException {
        // 获取套接字通道
        SocketChannel socketChannel = (SocketChannel) key.channel();
        // 获取缓冲器并进行重置,selectionKey.attachment()为获取选择器键的附加对象
        ByteBuffer buf = (ByteBuffer) key.attachment();
        if (socketChannel.read(buf) == -1) {
            System.out.println("没有消息内容");
            socketChannel.close();
            return;
        }
        // 将缓冲器转换为读状态
        buf.flip();
        // 将缓冲器中接收到的值按localCharset格式编码保存
        String receivedRequestData = Charset.forName(localCharset).newDecoder().decode(buf).toString();
        Result result = JSON.parseObject(receivedRequestData, Result.class);
        System.out.println("接收到客户端的Resule：" + result.toString());
        buf.clear();
        //为下一次读取或写入做准备
        key.interestOps(SelectionKey.OP_WRITE);
    }

    public void handleWrite(SelectionKey key) throws IOException {
        // 获取套接字通道
        SocketChannel socketChannel = (SocketChannel) key.channel();

        Result result = Result.getInstance();
        result.setCode(1);
        result.setData("测试");
        result.setSuccess(true);
        result.setMsg("谢谢你的连接");
        // 将对象转为json字符串
        String message = JSON.toJSONString(result);

        ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
        writeBuffer.clear();
        writeBuffer.put(message.getBytes(localCharset));
        writeBuffer.flip();
        while (writeBuffer.hasRemaining()) {
            socketChannel.write(writeBuffer);
        }
        writeBuffer.clear();
        // 压缩此缓冲区,以防后续写入数据不完整，从缓冲区写入数据之后调用此方法
        writeBuffer.compact();
        //为下一次读取或写入做准备
        key.interestOps(SelectionKey.OP_READ);
    }
}
